package com.errol.generic.baiducloud.portraitai;

import com.renjia.enums.AccessInterfaceBusinessTypeEnum;
import com.renjia.service.CoreLogIntegrationService;
import com.renjia.service.generic.baiducloud.basic.BaiduBasicService;
import com.renjia.service.generic.baiducloud.portraitai.pojo.BaiduPortraitAiConfig;
import com.renjia.service.generic.baiducloud.portraitai.pojo.BaiduPortraitSegmentResultDTO;
import com.renjia.service.generic.baiducloud.portraitai.pojo.BaiduPortraitSegmentTypeEnum;
import com.renjia.service.generic.http.HttpResult;
import com.renjia.service.generic.http.HttpService;
import com.renjia.service.generic.log.LogService;
import org.apache.commons.io.FileUtils;
import org.springframework.http.HttpMethod;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author zhang xiao bin
 * @version v1.0
 * @date 2020/09/21
 * @since v
 **/
@Service
public class BaiduPortraitAiServiceImpl implements BaiduPortraitAiService {

    /**
     * token 过期自动重试的时间
     */
    private long retryTime = 0;
    private final BaiduPortraitAiConfig config;
    private final BaiduBasicService baiduBasicService;
    private final HttpService httpService;
    private final LogService logService;
    private final CoreLogIntegrationService coreLogIntegrationService;

    public BaiduPortraitAiServiceImpl(BaiduPortraitAiConfig baiduPortraitAiConfig,
                                      BaiduBasicService baiduBasicService,
                                      HttpService httpService, LogService logService,
                                      CoreLogIntegrationService coreLogIntegrationService) {
        this.config = baiduPortraitAiConfig;
        this.baiduBasicService = baiduBasicService;
        this.httpService = httpService;
        this.logService = logService;
        this.coreLogIntegrationService = coreLogIntegrationService;
    }

    @NonNull
    @Override
    public BaiduPortraitSegmentResultDTO portraitSegment(@NonNull File image, @NonNull BaiduPortraitSegmentTypeEnum[] typeEnum) {
        long maxSize = 4 * 1024 * 1024L;
        if (image.length() > maxSize) {
            return new BaiduPortraitSegmentResultDTO(BaiduPortraitSegmentResultDTO.ResultStatus.IMAGE_TOO_BIG);
        }
        String accessToken = baiduBasicService.getAccessToken(config.getAppId(), config.getApiKey(), config.getSecretKey());
        long t = System.currentTimeMillis();
        if (accessToken != null) {
            String url = "https://aip.baidubce.com/rest/2.0/image-classify/v1/body_seg?access_token=" + accessToken;
            try {
                String imageBase64 = Base64.getEncoder().encodeToString(FileUtils.readFileToByteArray(image));
                if (imageBase64.length() > maxSize) {
                    return new BaiduPortraitSegmentResultDTO(BaiduPortraitSegmentResultDTO.ResultStatus.IMAGE_TOO_BIG);
                }
                HttpResult<BaiduPortraitSegmentResultDTO> httpResult = httpService.execute(httpService.builder(url)
                        .setConnectTimeout(10)
                        .setReadTimeout(10)
                        .usePost()
                        .sendFormData()
                        .addRequestBodyParam("image", imageBase64)
                        .addRequestBodyParam("type", Arrays.stream(typeEnum).map(BaiduPortraitSegmentTypeEnum::getTypeParam).collect(Collectors.joining(",")))
                        .expectJsonOfClass(BaiduPortraitSegmentResultDTO.class)
                        .build());
                if (httpResult.isSuccess()) {
                    if (httpResult.getData().getErrCode() != null) {
                        logService.warn("百度人像分割接口失败，code=" + httpResult.getData().getErrCode() + "，msg=" + httpResult.getData().getErrMsg());
                        coreLogIntegrationService.generateLog(AccessInterfaceBusinessTypeEnum.BAIDU_PORTRAIT_SEGMENT, image.getPath(), url, HttpMethod.POST, "",
                                "200", "请求失败 错误信息：" + httpResult.getData().getErrCode() + "-" + httpResult.getData().getErrMsg(), System.currentTimeMillis() - t);
                        // 可能是 token 无效的错误码，自动重试一次
                        List<Integer> tokenInvalidErrorCode = Arrays.asList(100, 110, 111);
                        if (tokenInvalidErrorCode.contains(httpResult.getData().getErrCode())) {
                            // 30 分钟内只会重试一次，避免出现死循环
                            if (retryTime == 0 || (System.currentTimeMillis() - retryTime) > (60000 * 30)) {
                                baiduBasicService.invalidAccessToken(config.getAppId());
                                retryTime = System.currentTimeMillis();
                                return portraitSegment(image, typeEnum);
                            }
                        }
                    } else {
                        httpResult.getData().setStatus(BaiduPortraitSegmentResultDTO.ResultStatus.SUCCESS);
                        coreLogIntegrationService.generateLog(AccessInterfaceBusinessTypeEnum.BAIDU_PORTRAIT_SEGMENT, image.getPath(), url, HttpMethod.POST, "",
                                "200", "请求成功 识别人数：" + httpResult.getData().getPersonNum(), System.currentTimeMillis() - t);
                        return httpResult.getData();
                    }
                }
            } catch (Exception e) {
                logService.error(e, "百度人像分割接口异常");
                coreLogIntegrationService.generateLog(AccessInterfaceBusinessTypeEnum.BAIDU_PORTRAIT_SEGMENT, image.getPath(), url, HttpMethod.POST, "",
                        "200", e.getMessage(), System.currentTimeMillis() - t);
            }
        }
        return new BaiduPortraitSegmentResultDTO(BaiduPortraitSegmentResultDTO.ResultStatus.FAILURE);
    }
}
